package role

import (
	"fmt"

	"github.com/Masterminds/squirrel"
	"github.com/gin-gonic/gin"
	"go-api-template/api/http"
	"go-api-template/api/models/system"
	e2 "go-api-template/internal/e"
	"go-api-template/service"
)

// SaveReq 创建/修改角色
type SaveReq struct {
	ID      string   `json:"id"`                      // 角色ID
	Name    string   `json:"name" binding:"required"` // 角色名
	MenuIds []string `json:"menu_ids"`                // 菜单ID列表
}
type SaveResp struct {
}

func (req *SaveReq) Request(ctx *gin.Context, s *service.Service) (http.Resp, error) {
	return req.Do(ctx, s)
}
func (req *SaveReq) Do(ctx *gin.Context, s *service.Service) (resp http.Resp, err error) {
	var data SaveResp
	var role system.Role
	role.Name = req.Name
	role.ID = req.ID

	if req.ID != "" {
		s.Db.Debug().Model(&role).
			Update("name", req.Name)

		// 删除所有授权
		rolePolicy := s.RBAC.GetFilteredPolicy(0, req.ID, "", "menu")
		for _, policy := range rolePolicy {
			obj := policy[1]
			_, _ = s.RBAC.RemovePolicy(req.ID, obj)
		}
	} else {
		s.Db.Debug().Model(&role).Where("name = ?", req.Name).Scan(&role)
		if role.ID != "" {
			resp.SetCode(e2.RoleNameRepeat)
			return
		}
		s.Db.Debug().Create(&role)
	}
	for _, id := range req.MenuIds {
		// 菜单授权
		_, _ = s.RBAC.AddPolicy(role.ID, id, "menu")

		s.Db.Create(&system.RoleMenu{
			RoleId: role.ID,
			MenuId: id,
		})
	}

	resp.SetData(data)
	return
}

// ListReq 角色列表
type ListReq struct {
	Name    string   `form:"name"`
	MenuIds []string `form:"menu_ids"`
	http.PaginationReq
}
type ListResp struct {
	http.RespList[ListRespItem]
}
type ListRespItem struct {
	ID      string   `json:"id"`
	Name    string   `json:"name"`
	MenuIds []string `json:"menu_ids"`
}

func (req *ListReq) Request(ctx *gin.Context, s *service.Service) (http.Resp, error) {
	return req.Do(ctx, s)
}
func (req *ListReq) Do(_ *gin.Context, s *service.Service) (resp http.Resp, err error) {
	var data ListResp
	var roles []system.Role

	req.query(s, &roles)

	data.Total = req.query(s, nil)
	for _, role := range roles {
		data.Items = append(data.Items, ListRespItem{
			ID:      role.ID,
			Name:    role.Name,
			MenuIds: nil,
		})
	}

	resp.SetData(data)
	return
}
func (req *ListReq) query(s *service.Service, items *[]system.Role) (count int) {
	itemsSq := squirrel.Select([]string{
		"r.*",
	}...).
		From("system_role r").
		LeftJoin("system_role_menu rm on rm.role_id = r.id").
		GroupBy("r.id")

	if req.Name != "" {
		itemsSq = itemsSq.Where("r.name like ?", fmt.Sprint("%", req.Name, "%"))
	}

	if len(req.MenuIds) != 0 {
		itemsSq = itemsSq.LeftJoin("rm.menu_id in ?", req.MenuIds)
	}

	if items == nil {
		countSq := squirrel.Select("count(1)")
		toSql, value, _ := itemsSq.ToSql()
		countSq = countSq.From(fmt.Sprintf("(%s)t", toSql))
		toSql, _, _ = countSq.ToSql()
		s.Db.Raw(toSql, value...).Scan(&count)
	} else {
		sql, value, _ := itemsSq.ToSql()
		s.Db.Raw(sql, value...).Debug().Scan(items)
	}
	return
}
